#include "driver.h"
#include "CancelSafeQueue.h"

extern IO_CSQ g_CancelSafeQueue;
extern LIST_ENTRY g_TransportIrpQueue;
extern KSPIN_LOCK g_QueueLock;
extern BOOLEAN isBeginLog;

NTSTATUS US_DispatchAny(IN PDEVICE_OBJECT fido, IN PIRP pIrp)
{							// US_DispatchAny
	PUSBFILTER_DEVICE_EXTENSION pdx = (PUSBFILTER_DEVICE_EXTENSION) fido->DeviceExtension;
	NTSTATUS status;

	//KdPrint((DRIVERNAME " - %s\n", "DispatchAny"));

	// Pass request down without additional processing

	status = IoAcquireRemoveLock(&pdx->RemoveLock, pIrp);
	if (!NT_SUCCESS(status))
		return US_CompleteRequest(pIrp, status, 0);
	IoSkipCurrentIrpStackLocation(pIrp);
	status = IoCallDriver(pdx->AttachedToDeviceObject, pIrp);
	IoReleaseRemoveLock(&pdx->RemoveLock, pIrp);
	return status;		
}							// US_DispatchAny

NTSTATUS US_DispatchIOCTL(IN PDEVICE_OBJECT fido, IN PIRP pIrp)
{
	PUSBFILTER_DEVICE_EXTENSION pdx = (PUSBFILTER_DEVICE_EXTENSION) fido->DeviceExtension;
	NTSTATUS status;
	PIRP pIrpOut;

	if(isBeginLog)
	{
		if(pdx->isWathDevice)
		{
			if (!US_PassPacketToUserMode(pIrp, FALSE))
			{
				KdPrint(("US_DispatchIOCTL: Queue is empty\n"));
			}
			status = IoAcquireRemoveLock(&pdx->RemoveLock, pIrp);
			if (!NT_SUCCESS(status))
			{
				return US_CompleteRequest(pIrp, status, 0);
			}
			IoCopyCurrentIrpStackLocationToNext(pIrp);
			
			//KEVENT myEvent;
			//KeInitializeEvent( &myEvent, NotificationEvent, FALSE );

			IoSetCompletionRoutine(pIrp, US_CompletionRoutine, 
						NULL,  TRUE, TRUE, TRUE);

			//KeWaitForSingleObject(&myEvent, Executive, KernelMode, FALSE,	NULL);

			status = IoCallDriver(pdx->AttachedToDeviceObject, pIrp);
			IoReleaseRemoveLock(&pdx->RemoveLock, pIrp);
			return status;
		}
	}



		status = IoAcquireRemoveLock(&pdx->RemoveLock, pIrp);
		if (!NT_SUCCESS(status))
			return US_CompleteRequest(pIrp, status, 0);
		IoSkipCurrentIrpStackLocation(pIrp);
		status = IoCallDriver(pdx->AttachedToDeviceObject, pIrp);
		IoReleaseRemoveLock(&pdx->RemoveLock, pIrp);
		return status;//*/
	
	/*	
		if(isBeginLog)
		if(pdx->isWathDevice)
		{
			US_PassPacketToUserMode(pIrp, FALSE);
			IoSetCompletionRoutine(pIrp, US_CompletionRoutine, 
									NULL,  TRUE, TRUE, TRUE);
		}

		//KdPrint((DRIVERNAME " - %s\n", "DispatchAny"));


		status = IoAcquireRemoveLock(&pdx->RemoveLock, pIrp);
		if (!NT_SUCCESS(status))
			return US_CompleteRequest(pIrp, status, 0);
		IoSkipCurrentIrpStackLocation(pIrp);
		status = IoCallDriver(pdx->AttachedToDeviceObject, pIrp);
		IoReleaseRemoveLock(&pdx->RemoveLock, pIrp);
		return status;//*/
}

///////////////////////////////////////////////////////////////////////////////

NTSTATUS US_DispatchPower(IN PDEVICE_OBJECT fido, IN PIRP Irp)
	{							// US_DispatchPower
	NTSTATUS status;
	PUSBFILTER_DEVICE_EXTENSION pdx = (PUSBFILTER_DEVICE_EXTENSION) fido->DeviceExtension;
#if DBG
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	ULONG fcn = stack->MinorFunction;

	static char* fcnname[] = {
		"IRP_MN_WAIT_WAKE",
		"IRP_MN_POWER_SEQUENCE",
		"IRP_MN_SET_POWER",
		"IRP_MN_QUERY_POWER",
		};

	if (fcn == IRP_MN_SET_POWER || fcn == IRP_MN_QUERY_POWER)
		{
		static char* sysstate[] = {
			"PowerSystemUnspecified",
			"PowerSystemWorking",
			"PowerSystemSleeping1",
			"PowerSystemSleeping2",
			"PowerSystemSleeping3",
			"PowerSystemHibernate",
			"PowerSystemShutdown",
			"PowerSystemMaximum",
			};

		static char* devstate[] = {
			"PowerDeviceUnspecified",
			"PowerDeviceD0",
			"PowerDeviceD1",
			"PowerDeviceD2",
			"PowerDeviceD3",
			"PowerDeviceMaximum",
			};

		ULONG context = stack->Parameters.Power.SystemContext;
		POWER_STATE_TYPE type = stack->Parameters.Power.Type;

		KdPrint((DRIVERNAME " - IRP_MJ_POWER (%s)", fcnname[fcn]));
		if (type == SystemPowerState)
			KdPrint((", SystemPowerState = %s\n", sysstate[stack->Parameters.Power.State.SystemState]));
		else
			KdPrint((", DevicePowerState = %s\n", devstate[stack->Parameters.Power.State.DeviceState]));
		}
	else 
		if (fcn < arraysize(fcnname))
			KdPrint((DRIVERNAME " - IRP_MJ_POWER (%s)\n", fcnname[fcn]));
		else
			KdPrint((DRIVERNAME " - IRP_MJ_POWER (%2.2X)\n", fcn));

#endif // DBG

	
	PoStartNextPowerIrp(Irp);	// must be done while we own the IRP
	status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);
	if (!NT_SUCCESS(status))
		return US_CompleteRequest(Irp, status, 0);
	IoSkipCurrentIrpStackLocation(Irp);
	status = PoCallDriver(pdx->AttachedToDeviceObject, Irp);
	IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
	return status;
	}							// US_DispatchPower

///////////////////////////////////////////////////////////////////////////////


NTSTATUS US_UsageNotificationCompletionRoutine(PDEVICE_OBJECT fido, PIRP Irp, PUSBFILTER_DEVICE_EXTENSION pdx)
	{							
		// UsageNotificationCompletionRoutine
	if (Irp->PendingReturned)
		IoMarkIrpPending(Irp);

	// If lower driver cleared pageable flag, we must do the same

	if (!(pdx->AttachedToDeviceObject->Flags & DO_POWER_PAGABLE))
		fido->Flags &= ~DO_POWER_PAGABLE;

	IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
	return STATUS_SUCCESS;
	}

NTSTATUS US_DispatchPnp(IN PDEVICE_OBJECT fido, IN PIRP Irp)
	{							// DispatchPnp
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	ULONG fcn = stack->MinorFunction;

	NTSTATUS status;
	PUSBFILTER_DEVICE_EXTENSION pdx = (PUSBFILTER_DEVICE_EXTENSION) fido->DeviceExtension;
	status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);
	if (!NT_SUCCESS(status))
		return US_CompleteRequest(Irp, status, 0);

#if DBG
	{
	static char* pnpname[] = {
		"IRP_MN_START_DEVICE",
		"IRP_MN_QUERY_REMOVE_DEVICE",
		"IRP_MN_REMOVE_DEVICE",
		"IRP_MN_CANCEL_REMOVE_DEVICE",
		"IRP_MN_STOP_DEVICE",
		"IRP_MN_QUERY_STOP_DEVICE",
		"IRP_MN_CANCEL_STOP_DEVICE",
		"IRP_MN_QUERY_DEVICE_RELATIONS",
		"IRP_MN_QUERY_INTERFACE",
		"IRP_MN_QUERY_CAPABILITIES",
		"IRP_MN_QUERY_RESOURCES",
		"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
		"IRP_MN_QUERY_DEVICE_TEXT",
		"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
		"",
		"IRP_MN_READ_CONFIG",
		"IRP_MN_WRITE_CONFIG",
		"IRP_MN_EJECT",
		"IRP_MN_SET_LOCK",
		"IRP_MN_QUERY_ID",
		"IRP_MN_QUERY_PNP_DEVICE_STATE",
		"IRP_MN_QUERY_BUS_INFORMATION",
		"IRP_MN_DEVICE_USAGE_NOTIFICATION",
		"IRP_MN_SURPRISE_REMOVAL",
		"IRP_MN_QUERY_LEGACY_BUS_INFORMATION",
		};

	if (fcn < arraysize(pnpname))
		KdPrint((DRIVERNAME " - IRP_MJ_PNP (%s)\n", pnpname[fcn]));
	else
		KdPrint((DRIVERNAME " - IRP_MJ_PNP (%2.2X)\n", fcn));
	}

#endif // DBG

	// Handle usage notification specially in order to track power pageable
	// flag correctly. We need to avoid allowing a non-pageable handler to be
	// layered on top of a pageable handler.

	if (fcn == IRP_MN_DEVICE_USAGE_NOTIFICATION)
		{						// usage notification
		if (!fido->AttachedDevice || (fido->AttachedDevice->Flags & DO_POWER_PAGABLE))
			fido->Flags |= DO_POWER_PAGABLE;
		IoCopyCurrentIrpStackLocationToNext(Irp);
		IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) US_UsageNotificationCompletionRoutine,
			(PVOID) pdx, TRUE, TRUE, TRUE);
		return IoCallDriver(pdx->AttachedToDeviceObject, Irp);
		}						// usage notification

	// Handle start device specially in order to correctly inherit
	// FILE_REMOVABLE_MEDIA

	if (fcn == IRP_MN_START_DEVICE)
		{						// device start
		IoCopyCurrentIrpStackLocationToNext(Irp);
		IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) US_StartDeviceCompletionRoutine,
			(PVOID) pdx, TRUE, TRUE, TRUE);
		return IoCallDriver(pdx->AttachedToDeviceObject, Irp);
		}						// device start

	// Handle remove device specially in order to cleanup device stack

	if (fcn == IRP_MN_REMOVE_DEVICE)
		{						// remove device
		IoSkipCurrentIrpStackLocation(Irp);
		status = IoCallDriver(pdx->AttachedToDeviceObject, Irp);
		IoReleaseRemoveLockAndWait(&pdx->RemoveLock, Irp);
		US_RemoveDevice(fido);
		return status;
		}						// remove device

	// Simply forward any other type of PnP request

	IoSkipCurrentIrpStackLocation(Irp);
	status = IoCallDriver(pdx->AttachedToDeviceObject, Irp);
	IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
	return status;
	}							// DispatchPnp

//////////////////////////////////////////////////////////////////
NTSTATUS US_DispatchCreate(IN PDEVICE_OBJECT pDevice, IN PIRP pIrp)
{
    KdPrint(("[DEBUG] " __FUNCTION__));

    pIrp->IoStatus.Information  = 0;
    pIrp->IoStatus.Status       = STATUS_SUCCESS;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}

/////////////////////////////////////////////////////////////////////
NTSTATUS US_DispatchClose(IN PDEVICE_OBJECT pDevice, IN PIRP pIrp)
{
    KdPrint(("[DEBUG] " __FUNCTION__));

	

    pIrp->IoStatus.Information  = 0;
    pIrp->IoStatus.Status       = STATUS_SUCCESS;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}
